﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_FLOAT_TYPE_H
#define _UXS_FLOAT_TYPE_H

#pragma once

#include "Types.h"
#include "AllFunc.h"

namespace UX_STL
{
namespace UXTypes
{
	
#	define _FLOAT_OPERATOR_E( _op, _ret0, _func0, _ret1, _func1, _ret2, _func2, _ret3, _func3 ) \
		template <typename T>		 _ret0 operator _op##= (const T& right)					_func0 \
									 _ret1 operator _op  (const Self& right) const			_func1 \
		template <typename T>		 _ret2 operator _op  (const T& right) const				_func2 \
		template <typename T> friend _ret3 operator _op  (const T& left, const Self& right) _func3 \

#	define _FLOAT_OPERATOR( _op ) \
		_FLOAT_OPERATOR_E( _op, \
				Self &,	{ _f _op##= FT(right);  return *this; }, \
				Self,		{ return _f _op right._f; }, \
				Self,		{ return _f _op FT(right); }, \
				T,			{ return left _op (T)right; } ) \
				
#	define _FLOAT_OPERATOR_B( _op ) \
		_FLOAT_OPERATOR_E( _op, \
				Self &,	{ _i _op##= IT(right);  return *this; }, \
				Self,		{ return Self(*this) |= right._i; }, \
				Self,		{ return Self(*this) |= right; }, \
				T,			{ return left | T(right._i); } ) \



	//
	// Floating Point Type
	//

	template <typename FT, typename IT, typename UT, usize Mbits, usize Ebits>
	struct TFloat
	{
		// types
		typedef TFloat<FT,IT,UT,Mbits,Ebits>	Self;
		typedef IT								Int_t;
		typedef UT								UInt_t;
		typedef FT								Float_t;

		struct TFloatBits
		{
			UT	m	: Mbits;	// mantissa bits
			UT	e	: Ebits;	// exponent bits
			UT	s	: 1;		// sign bit
		};


		// variables
		union {
			TFloatBits	_bits;
			FT			_f;
			IT			_i;
		};


		// constructors
		TFloat (): _f(FT(0))								{}
		TFloat (const Self &f): _f(f._f)					{}

		template <typename B>
		explicit
		TFloat (const B& val): _f(FT(val))					{}
	

		// type cast
		operator FT & ()									{ return _f; }
		operator const FT () const							{ return _f; }
	

		// unary operators
		Self &	operator ++ ()								{ ++_f; return *this; }
		Self &	operator -- ()								{ --_f; return *this; }
		Self	operator ++ (int) 							{ Self temp(*this);  ++_f;  return temp; }
		Self	operator -- (int) 							{ Self temp(*this);  --_f;  return temp; }
		IT		operator ~ ()	const						{ return ~_i; }
		bool	operator ! ()	const						{ return not _f; }


		// binary operators
#	if 0
		template <typename T>	bool	operator ==  (const T& right) const	{ return Equal( FT(right) ); }
		template <typename T>	bool	operator >=  (const T& right) const	{ const FT f(right);  return _f > f ||  Equal(f); }
		template <typename T>	bool	operator >   (const T& right) const	{ const FT f(right);  return _f > f and not Equal(f); }
		template <typename T>	bool	operator <=  (const T& right) const	{ const FT f(right);  return _f < f ||  Equal(f); }
		template <typename T>	bool	operator <   (const T& right) const	{ const FT f(right);  return _f < f and not Equal(f); }
#	endif

		
		_FLOAT_OPERATOR( + );
		_FLOAT_OPERATOR( - );
		_FLOAT_OPERATOR( * );
		_FLOAT_OPERATOR( / );
		_FLOAT_OPERATOR_E( %,
				Self&,	{ _f = ::_hidden_::fmod( _f, right );  return *this; },
				Self,	{ return ::_hidden_::fmod( _f, right._f ); },
				Self,	{ return ::_hidden_::fmod( _f, right ); },
				T,		{ return ::_hidden_::fmod( left, (T)right ); }
		);
		_FLOAT_OPERATOR_B( |  );
		_FLOAT_OPERATOR_B( &  );
		_FLOAT_OPERATOR_B( ^  );
		_FLOAT_OPERATOR_E( >>,
				Self&,	{ return FastPow2( -right ); },
				Self,	{ return Self(*this) >>= right._i; },
				Self,	{ return Self(*this) >>= right; },
				T,		{ return left >> (T)right; }
		);
		_FLOAT_OPERATOR_E( <<,
				Self&,	{ return FastPow2( right ); },
				Self,	{ return Self(*this) <<= right._i; },
				Self,	{ return Self(*this) <<= right; },
				T,		{ return left << (T)right; }
		);

		Self &	operator |=  (const Self& right)		{ _i |= right._i;  return *this; }
		Self &	operator &=  (const Self& right)		{ _i &= right._i;  return *this; }
		Self &	operator ^=  (const Self& right)		{ _i ^= right._i;  return *this; }


		// methods
		static usize	Mantissa()						{ return Mbits; }
		static usize	Exponent()						{ return Ebits; }

		static Self		FromBits (TFloatBits bits)		{ Self res;  res._bits = bits;  return res; }

		void	SetF(const FT &f)						{ _f = f; }
		void	SetI(const IT &i)						{ _i = i; }
		FT		GetF()				const				{ return _f; }
		IT		GetI()				const				{ return _i; }
		FT &	GetFRef()								{ return _f; }
		IT &	GetIRef()								{ return _i; }
		IT		GetMantissaBit()	const				{ return _bits.m; }
		IT		GetExponentBit()	const				{ return IT(_bits.e) - (1<<(Ebits-1)) + 1; }
		int8	GetSign()			const				{ return _bits.s ? -1 : 1; }

		FT		GetMantissa()		const				{ return FT(1) + FT(_bits.m) / FT( (1<<Mbits)-1 ); }
		FT		GetExponent()		const;

		Self &	FastPow2(int off)						{ _bits.e += off;  return *this; }

		
		// checks
		STATIC_ASSERT( sizeof(FT)  == sizeof(IT), "types size mismatch" );
	};
	

	// types
	typedef TFloat< float,  int,   uint,   23,  8 >		float32_t;
	typedef TFloat< double, int64, uint64, 52, 11 >		float64_t;


	template <typename T>	struct TFloatSimilar;
	template <>				struct TFloatSimilar<float>		{ typedef float32_t		type; };
	template <>				struct TFloatSimilar<double>	{ typedef float64_t		type; };
	template <>				struct TFloatSimilar<float32_t>	{ typedef float32_t		type; };
	template <>				struct TFloatSimilar<float64_t>	{ typedef float64_t		type; };


/*
=================================================
	
=================================================
*/
	template <typename FT, typename IT, typename UT, usize Mbits, usize Ebits>
	inline FT TFloat<FT,IT,UT,Mbits,Ebits>::GetExponent() const
	{
		IT	p = GetExponentBit();

		if ( p >= 0 )
			return FT( IT(1) << p );
		else
			return FT(1) / FT( IT(1) << (-p) ); 
	}


#	undef _FLOAT_OPERATOR

//-------------------------------------------------------------------

}	// UXMath
}	// UX_STL

#endif	// _UXS_FLOAT_TYPE_H